/*!	 synfig/rendering/opengl/internal/context.h
**	 Context Header
**
**	......... ... 2015 Ivan Mahonin
**
**	This package is free software; you can redistribute it and/or
**	modify it under the terms of the GNU General Public License as
**	published by the Free Software Foundation; either version 2 of
**	the License, or (at your option) any later version.
**
**	This package is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
**	General Public License for more details.
**
*/

#ifndef __SYNFIG_RENDERING_GL_CONTEXT_H
#define __SYNFIG_RENDERING_GL_CONTEXT_H

#include <cassert>

#include <vector>
#include <utility>

#include <glibmm/threads.h>

#include <GL/gl.h>
#include <GL/glx.h>

#include <synfig/string.h>

namespace synfig
{
namespace rendering
{
namespace gl
{

class Context
{
public:
    class Lock
    {
    private:
        Context &context;
    public:
        Lock(Context &context): context(context)
        {
            context.use();
        }
        Lock(Lock &other): context(other.context)
        {
            context.use();
        }
        ~Lock()
        {
            context.unuse();
        }

        Context& get() const
        {
            return context;
        }
        Context* operator-> () const
        {
            return &get();
        }
    };

    struct ContextInfo {
        Display *display;
        GLXDrawable drawable;
        GLXDrawable read_drawable;
        GLXContext context;

        ContextInfo():
            display(NULL),
            drawable(None),
            read_drawable(None),
            context(NULL) { }

        bool operator== (const ContextInfo &other) const
        {
            return display == other.display
                   && drawable == other.drawable
                   && read_drawable == other.read_drawable
                   && context == other.context;
        }

        bool operator!= (const ContextInfo &other) const
        {
            return !(*this == other);
        }

        void make_current() const;
        static ContextInfo get_current(Display *default_display);
    };

private:
    Glib::Threads::RecMutex rec_mutex;

    Display *display;
    GLXFBConfig config;
    GLXPbuffer pbuffer;
    GLXContext context;

    ContextInfo context_info;
    std::vector<ContextInfo> context_stack;

    static std::pair<GLenum, const char*> enum_strings[];

public:
    Context();
    ~Context();

    bool is_valid() const
    {
        return context;
    }
    bool is_current() const;
    void use();
    void unuse();

    void check(const char *s = "");
    const char* get_enum_string(GLenum x);
};

}; /* end namespace gl */
}; /* end namespace rendering */
}; /* end namespace synfig */

#endif